﻿
#include "stdafx.h"
#include "colordef.h"
#include "alpha_x86.inl"
#include "alpha_sse.inl"

//////////////////////////////////////////////////////////////////////////

VOID CCALL AlphaBlend32LevelSSE(WORD src, LPVOID dest, UINT pitch, UINT cx, UINT height, BYTE alpha)
{
	static const QWORD COLORMASK = 0x07e0f81f07e0f81f;
	static const QWORD THREETHREE = 0x0003000300030003;

	LPBYTE line = static_cast<LPBYTE>(dest);
	BYTE alpha_p[] = { alpha, alpha };
	WORD src_p[] = { src, src };

	__asm
	{
		movq		mm4, THREETHREE
		movq		mm5, COLORMASK
	}

	UINT loop = cx >> 1;

	if (cx & 0x1)
	{
		for (; height; height--, line += pitch)
		{
			LPWORD img = reinterpret_cast<LPWORD>(line);

			for (UINT i = loop; i; i--, img += 2)
				AlphaBlend32LevelSSE(src_p, img, alpha_p);

			AlphaBlend32LevelX86(src_p, img, alpha_p);
		}
	}
	else
	{
		for (; height; height--, line += pitch)
		{
			LPWORD img = reinterpret_cast<LPWORD>(line);

			for (UINT i = loop; i; i--, img += 2)
				AlphaBlend32LevelSSE(src_p, img, alpha_p);
		}
	}

	__asm emms
}

VOID CCALL AlphaBlend32LevelSSE(LPCVOID src, UINT src_pitch, LPVOID dest, UINT dest_pitch, LPCVOID alpha, UINT alpha_pitch, UINT width, UINT height)
{
	static const QWORD COLORMASK = 0x07e0f81f07e0f81f;
	static const QWORD THREETHREE = 0x0003000300030003;

	DWORD	cnt;
	DWORD	srl = src_pitch - (width << 1);
	DWORD	drl = dest_pitch - (width << 1);
	DWORD	arl = alpha_pitch - width;

#if 1
	__asm
	{
		mov			edx, width			// [0][M]
		mov			ebx, height			// [0][M]
		mov			esi, src			// [0][M]
		mov			edi, dest			// [0][M]
		mov			eax, alpha			// [0][M]
		movq		mm5, COLORMASK		// [0][M]
//		test		edx, 01h			// [0]
//		jnz			width_odd			// [0][J]

		// width为偶数
		shr			edx, 2				// [0]
		mov			cnt, edx

line_loop:
		test		ebx, ebx			// [1]
		jz			done				// [1][J]

pixel_loop:
		test		edx, edx			// [2]
		jz			end_line			// [2][J]

		// 一次性装载4个APLHA到mm7
		mov			ecx, [eax]			// [2][M]
		test		ecx, ecx			// [2]
		jz			pixel_end			// [2][J] 如果ALPHA都为0，跳过
		movd		mm7, ecx			// [2] mm7 = 00 00 00 00 a3 a2 a1 a0
		pxor		mm4, mm4			// [2] mm4 = 0

		// 分别一次性装载源和目标的4个像素到mm0和mm1
		movq		mm0, [esi]			// [2][M] mm0 = s3 s2 s1 s0
		movq		mm1, [edi]			// [2][M] mm1 = d3 d2 d1 d0

		// 分组扩展ALPHA和像素
		punpcklbw	mm7, mm4			// [2] mm7 = 00 a3 00 a2 00 a1 00 a0
		movq		mm2, mm0			// [2] mm2 = s3 s2 s1 s0
		movq		mm3, mm1			// [2] mm3 = d3 d2 d1 d0
		paddw		mm7, THREETHREE		// [2] ALPHA误差补正
		punpcklwd	mm0, mm0			// [2] mm0 = s1[rgbrgb] s0[rgbrgb]
		punpcklwd	mm1, mm1			// [2] mm1 = d1[rgbrgb] d0[rgbrgb]
		psrlw		mm7, 3				// [2] 只保留32级ALPHA
		punpckhwd	mm2, mm2			// [2] mm2 = s3[rgbrgb] s2[rgbrgb]
		punpckhwd	mm3, mm3			// [2] mm3 = d3[rgbrgb] d2[rgbrgb]
		movq		mm6, mm7			// [2] mm6 = 00 a3 00 a2 00 a1 00 a0
		pand		mm0, mm5			// [2] mm0 = s1[.g.r.b] s0[.g.r.b]
		pand		mm1, mm5			// [2] mm1 = d1[.g.r.b] d0[.g.r.b]
		punpcklwd	mm7, mm7			// [2] mm7 = 00 a1 00 a1 00 a0 00 a0
		pand		mm2, mm5			// [2] mm2 = s3[.g.r.b] s2[.g.r.b]
		pand		mm3, mm5			// [2] mm3 = d3[.g.r.b] d2[.g.r.b]
		punpckhwd	mm6, mm6			// [2] mm6 = 00 a3 00 a3 00 a2 00 a2

		// 混色计算（从SSE开始终于支持16位无符号乘法了，仅这一点就有性能提升）
		psubd		mm0, mm1			// [2] mm0 = s1s0 - d1d0
		psubd		mm2, mm3			// [2] mm2 = s3s2 - d3d2

		movq		mm4, mm0			// [2] mm4 = mm0
		pmullw		mm0, mm7			// [2][L] mm0 = c1[gx.xbx] c0[gx.xbx]
		pmulhuw		mm4, mm7			// [2][L] mm4 = c1[.....r] c0[.....r]
		pslld		mm4, 16				// [2] mm4 = c1[..r...] c0[..r...]
		paddd		mm0, mm4			// [2] mm0 = c1[gxrxbx] c0[gxrxbx]
		psrld		mm0, 5				// [2] mm0 = c1[.gxrxb] c0[.gxrxb]
		paddd		mm0, mm1			// [2] mm0 = c1c0 + d1d0
		pand		mm0, mm5			// [2] mm0 = c1[.g.r.b] c0[.g.r.b]

		movq		mm4, mm2			// [2] mm4 = mm2
		pmullw		mm2, mm6			// [2][L] mm2 = c3[gx.xbx] c2[gx.xbx]
		pmulhuw		mm4, mm6			// [2][L] mm4 = c3[.....r] c2[.....r]
		pslld		mm4, 16				// [2] mm4 = c3[..r...] c2[..r...]
		paddd		mm2, mm4			// [2] mm2 = c3[gxrxbx] c2[gxrxbx]
		psrld		mm2, 5				// [2] mm2 = c3[.gxrxb] c2[.gxrxb]
		paddd		mm2, mm3			// [2] mm2 = c3c2 + d3d2
		pand		mm2, mm5			// [2] mm2 = c3[.g.r.b] c2[.g.r.b]

		// 恢复像素
		pshufw		mm1, mm0, 0b1h		// [2] mm1 = c1[r.b.g.] c0[r.b.g.]
		pshufw		mm3, mm2, 0b1h		// [2] mm3 = c3[r.b.g.] c2[r.b.g.]
		por			mm1, mm0			// [2] mm1 = c1[rgbrgb] c0[rgbrgb]
		por			mm3, mm2			// [2] mm3 = c3[rgbrgb] c2[rgbrgb]
		pshufw		mm0, mm1, 0d8h		// [2] mm0 = c1 c0 c1 c0
		pshufw		mm2, mm3, 0d8h		// [2] mm2 = c3 c3 c2 c2
		punpckldq	mm0, mm2			// [2] mm0 = c3 c2 c1 c0

		// 保存结果
		movq		[edi], mm0

pixel_end:
		dec			edx					// [2]
		add			esi, 8				// [2]
		add			edi, 8				// [2]
		add			eax, 4				// [2]
		jmp			pixel_loop			// [2]

end_line:
		dec			ebx					// [1]
		mov			edx, cnt			// [1][M]
		add			esi, srl			// [1][M]
		add			edi, drl			// [1][M]
		add			eax, arl			// [1][M]
		jmp			line_loop			// [1]

width_odd:
		shr			edx, 1				// [0]

done:
		emms
	}

#else
	LPCBYTE src_ln = static_cast<LPCBYTE>(src);
	LPBYTE dest_ln = static_cast<LPBYTE>(dest);
	LPCBYTE alpha_ln = static_cast<LPCBYTE>(alpha);

	__asm
	{
		movq		mm4, THREETHREE
		movq		mm5, COLORMASK
	}

	UINT loop = width >> 1;

	if (width & 0x1)
	{
		for (; height; height--, src_ln += src_pitch, dest_ln += dest_pitch, alpha_ln += alpha_pitch)
		{
			LPCWORD src_ptr = reinterpret_cast<LPCWORD>(src_ln);
			LPWORD dest_ptr = reinterpret_cast<LPWORD>(dest_ln);
			LPCBYTE alpha_ptr = alpha_ln;

			for (UINT i = loop; i; i--, src_ptr += 2, dest_ptr += 2, alpha_ptr += 2)
				AlphaBlend32LevelSSE(src_ptr, dest_ptr, alpha_ptr);

			AlphaBlend32LevelX86(src_ptr, dest_ptr, alpha_ptr);
		}
	}
	else
	{
		for (; height; height--, src_ln += src_pitch, dest_ln += dest_pitch, alpha_ln += alpha_pitch)
		{
			LPCWORD src_ptr = reinterpret_cast<LPCWORD>(src_ln);
			LPWORD dest_ptr = reinterpret_cast<LPWORD>(dest_ln);
			LPCBYTE alpha_ptr = alpha_ln;

			for (UINT i = loop; i; i--, src_ptr += 2, dest_ptr += 2, alpha_ptr += 2)
				AlphaBlend32LevelSSE(src_ptr, dest_ptr, alpha_ptr);
		}
	}

	__asm emms
#endif
}

//////////////////////////////////////////////////////////////////////////
